package csm.common.configuration;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.DefaultConfigurationBuilder;

/**
 * 
 * @author seungmun
 * @since 2006.1.18.
 * @version
 * @see
 */
public final class ConfigHandler
{
	private static ConfigHandler configHandler = null;

	/**
     * 생성된 ConfigHandler Instance를 리턴한다.
     * 
     * <blockquote> 
     * 응용프로그램내 어딘가에서 최초 한번은 반드시 호출해 주어야 합니다.
     * 예를 들어 WebApplication은 StartupServlet에서 호출하도록 설정하면 된다.
     * </blockquote>
	 * 
	 * @param configFile
	 *            환경설정파일명(Path포함)
	 * @return ConfigHandler instance
	 */
	public synchronized static ConfigHandler getInstance(String configFile)
	{
		if (configHandler == null) configHandler = new ConfigHandler(configFile);
		return configHandler;
	}

	/**
	 * 생성된 ConfigHandler Instance를 리턴한다.
	 * 
	 * <blockquote> 
	 * 응용프로그램내 어딘가에서 최초 한번은 반드시 호출해 주어야 합니다.
	 * 예를 들어 WebApplication은 StartupServlet에서 호출하도록 설정하면 된다.
	 * </blockquote>
	 * 
	 * @return ConfigHandler instance
	 */
	public synchronized static ConfigHandler getInstance()
	{
		if (configHandler == null) configHandler = new ConfigHandler();
		return configHandler;
	}

	private Configuration config = null;
	private String configFileName = "config/config.xml";

	/**
	 * 기본생성
	 */
	private ConfigHandler()
	{
	}

	/**
	 * 기본생성자
	 * 
	 * @param configFile
	 *            환경설정파일명(Path포함)
	 */
	protected ConfigHandler(String configFile)
	{
		this.configFileName = configFile;
	}

	/**
	 * 설정에 접근할 수 있는 객체를 가져옵니다.
	 * @return {@link org.apache.commons.configuration.Configuration}
	 */
	public Configuration getConfiguration()
	{
		try
		{
			DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(this.configFileName);
			config = builder.getConfiguration(true);
		}
		catch (ConfigurationException e)
		{
			e.printStackTrace();
			config = null;
		}
		return config;
	}

	/**
	 * Configuration의 SubSet을 리턴한다. 리턴 받은 Configuration 객체를 통해서 각 ConfigHandler에서
	 * 해당 환경설정 내용을 조회하면 된다.
	 * 
	 * @param configName
	 *            subset 이름
	 * @see {@link org.apache.commons.configuration.Configuration}
	 */
	public Configuration getConfiguration(String configName)
	{
		if (config == null)
			config = getConfiguration();

		if (config != null) 
			return config.subset(configName);

		return null;
	}

	@SuppressWarnings("unchecked")
	public static void main(String[] args)
	{
		ConfigHandler cf = ConfigHandler.getInstance("config.xml");
		Configuration c = cf.getConfiguration();

		System.out.println(c.getString("connection(1)[@name]"));

		List<Object> list = c.getList("connection");
		System.out.println(list.size());

		Properties plist = c.getProperties("connection");
		System.out.println(plist.size());

		HashMap<String, HashMap<String, String>> configItems = new HashMap<String, HashMap<String, String>>();
		Object prop = c.getProperty("connection.dbms");
		if (prop instanceof Collection)
		{
			System.out.println("Number of connection: " + ((Collection<?>) prop).size());

			HashMap<String, String> configItem = null;

			int connectionSettingCount = ((Collection<?>) prop).size();

			String connectionPrefix = "";
			String connectionName = "";
			for (int i = 0; i < connectionSettingCount; i++)
			{
				connectionPrefix = String.format("connection(%s)", i);
				connectionName = c.getString(connectionPrefix + "[@name]");
				System.out.println("------");
				System.out.println(connectionName);
				configItem = new HashMap<String, String>();
				Iterator<String> is = c.getKeys(connectionPrefix);
				while (is.hasNext())
				{
					String elementName = is.next();
					System.out.println(elementName.replace(connectionPrefix, "connection") + ":" + c.getString(elementName));
					configItem.put(elementName.replace(connectionPrefix, "connection"), c.getString(elementName));
				}

				configItems.put(connectionName, configItem);
			}
		}

		System.out.println(configItems.get("anotherDB").get("connection.user"));

		return;
	}
}
